using System;
using Game.Framework;
using Unity.Collections;
using Unity.Entities;
using Unity.Jobs;

namespace Game.Core
{
    public delegate void EventHandler<TEventArgs>(Entity entity, TEventArgs args);
    
    public abstract class EventScheduler
    {
        protected World World;
        protected SystemBase System;
        
        protected static EndSimulationEntityCommandBufferSystem ECBSystem;
        protected EntityCommandBuffer ECB;
        protected EntityCommandBuffer.ParallelWriter ECBParallel;

        public static void Dispatch(JobHandle handle) => ECBSystem.AddJobHandleForProducer(handle);

        // public abstract void Init(SystemBase system);
        // public abstract JobHandle Schedule(JobHandle handle);
    }

    
    public class EventScheduler<TEvent> : EventScheduler, IScheduler
        where TEvent : unmanaged, IComponentData
    {
        public static EntityArchetype Archetype;
        public static EventHandler<TEvent> EventHandler;
        public EntityQuery m_EventQuery;

        public EventScheduler(SystemBase system)
        {
            World = system.World;
            System = system;
            ECBSystem = World.GetOrCreateSystemManaged<EndSimulationEntityCommandBufferSystem>();
            Archetype = World.EntityManager.CreateArchetype(typeof(TEvent));
            Init(system);
        }

        public void Init(SystemBase system)
        {
            var builder = new EntityQueryBuilder(Allocator.Temp);
            builder.AddAll(ComponentType.ReadOnly<TEvent>());
            // builder.FinalizeQuery();
            m_EventQuery = system.GetEntityQuery(builder);
        }

        public JobHandle Schedule(JobHandle handle = new JobHandle())
        {
            ECB = ECBSystem.CreateCommandBuffer();
            ECBParallel = ECB.AsParallelWriter();
            var job = new InvokeEventJob<TEvent>();
            job.ECBParallel = ECBParallel;
            job.EntityTypeHandle = System.GetEntityTypeHandle();
            job.EventTypeHandle = System.GetComponentTypeHandle<TEvent>();
            job.Run(m_EventQuery);
            return handle;
        }

        public static EventDispatcher<TEvent> CreateEventDispatcher() =>
            new EventDispatcher<TEvent>(Archetype, ECBSystem.CreateCommandBuffer());
    }
}